/*
 *     This file is part of Neptune Network Emulator.
 *
 *  Neptune Network Emulator is free software: 
 *  you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Neptune Network Emulator is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Neptune Network Emulator.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
/**
 *
 */
package neptune.web.server.operations;

import it.robertobifulco.ias.IncorrectParamsException;
import it.robertobifulco.ias.Operation;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import neptune.manager.NeptuneManager;
import neptune.manager.connector.Connector;
import neptune.manager.model.cluster.PhysicalNode;
import neptune.manager.model.template.VmTemplate;
import neptune.manager.model.topology.Node;
import neptune.manager.model.topology.Software;
import neptune.manager.storage.VmTemplateRepository;
import neptune.web.server.ApplicationManager;

/**
 * @author Roberto Bifulco [info@RobertoBifulco.it] [RobertoBifulco.it]
 * 
 */
public class SaveNodeAsTemplate implements Operation {

	public static String ID = "SaveNodeAsTemplate";

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.robertobifulco.ias.Operation#execute(java.lang.Object[])
	 */
	/**
	 * @param args
	 *            [0] = String nodeId - identificativo completo del nodo da
	 *            avviare
	 * @param args
	 *            [1] = PhysicalNode pm - identificativo della macchina che
	 *            ospita il nodo
	 * @param args
	 *            [2] = String templateName - the VM template name
	 * @return String lo stato attuale del nodo
	 */
	public Object[] execute(Object[] args) throws IncorrectParamsException,
			Exception {

		String nodeId = (String) args[0];
		PhysicalNode pm = (PhysicalNode) args[1];
		String templateName = (String) args[2];

		if (pm == null)
			throw new Exception("Unable to execute operation because the '"
					+ nodeId + "' hoster was not found.");

		String expsVMsDir = ApplicationManager.getApplicationManager()
				.getConfigRepository().getExperimentsVMsDir();
		String nodeImgPath = expsVMsDir + nodeId + ".img";

		Connector conn = ApplicationManager.getApplicationManager()
				.getNeptuneManager().getConnector(pm.getId());

		conn.swapOutVM(nodeId);

		File imgFile = new File(nodeImgPath);
		if (!imgFile.exists())
			throw new Exception("Node '" + nodeId + "' image file not found!");

		VmTemplateRepository templateRepository = ApplicationManager
				.getApplicationManager().getNeptuneManager()
				.getVmTemplateRepository();

		String expId = NeptuneManager.getExpNameFromNodeFullID(nodeId);
		String nodeSimpleId = NeptuneManager.getNodeNameFromNodeFullID(nodeId);
		Node node = NeptuneManager.instance().getExperiment(expId)
				.getTopology().searchNodeIntoTopology(nodeSimpleId);
		if (node == null)
			throw new Exception("Unable to find node '" + nodeId
					+ "' description!");

		VmTemplate template = new VmTemplate();
		template.setId(templateName);
		template.setControlPort(node.getControlPort());
		template.setOperativeSystem(node.getOperativeSystem());
		List<Software> softwaresList = Arrays.asList(node
				.getInstalledSoftwares());
		ArrayList<Software> softwares = new ArrayList<Software>(0);
		softwares.addAll(softwaresList);
		template.setSoftwares(softwares);

		templateRepository
				.addVmTemplate(template, new FileInputStream(imgFile));

		String[] macAddresses = new String[node.getInterfaces().length];
		for (int i = 0; i < macAddresses.length; i++)
			macAddresses[i] = node.getInterfaces()[i].getMacAddress()
					.getAddress();

		conn.swapInVM(nodeId, nodeImgPath, node.getRam(), macAddresses, null);
		conn.closeConnection();

		return new Object[] { Node.Status.RUNNING.toString() };
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.robertobifulco.ias.Operation#getDescription()
	 */
	public String getDescription() {
		return "Save the given node image in order to use it "
				+ "as a Virtual Machine template for future experiments.";
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see it.robertobifulco.ias.Operation#getID()
	 */
	public String getID() {
		return ID;
	}

}
